package cn.bellychang.bobo.binarysearch;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

/**
 * @author ChangLiang
 * @date 2021/2/4
 */
public class IpAddressSearch {

    private static final HashMap<IpPair, String> originPair = new HashMap<>(6);

    static{
        originPair.put(new IpPair("202.102.133.0", "202.102.133.255"), "山东东营");
        originPair.put(new IpPair("202.102.135.0", "202.102.136.255"), "山东烟台");
        originPair.put(new IpPair("202.102.134.34", "202.102.134.255"), "山东青岛");
        originPair.put(new IpPair("202.102.131.0", "202.102.131.255"), "江苏宿迁");
        originPair.put(new IpPair("202.102.136.0", "202.102.136.255"), "江苏泰州");
        originPair.put(new IpPair("202.102.132.0", "202.102.132.255"), "江苏连云港");
    }

    public static String getIpLocation(String ipStr) {

        Integer target = convertIpStr2Integer(ipStr);

        // 使用TreeMap 利用Long自然的排序方式
        TreeMap<Integer, String> ipLongHashMap = getIpLongHashMap();
        Integer[] data = new Integer[ipLongHashMap.size()];
        int i = 0;
        for (Map.Entry<Integer, String> entry : ipLongHashMap.entrySet()) {
            data[i++] = entry.getKey();
        }
        // binary search: 在一个有序数组中 找到大于此longIp的最大值  默认是连续的，不重复的，不包含空洞
        if (target < data[0] || target > data[data.length - 1]) {
            return "not found";
        }

        int l = 0;
        int r = data.length - 1;
        // upperFloor 或者 lowerCeil
        while (l < r) {
            int mid = l + ((r - l) >> 1);
            if (data[mid] < target) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        return ipLongHashMap.get(data[l]);
    }


    private static TreeMap<Integer, String> getIpLongHashMap() {
        TreeMap<Integer, String> longIpMap = new TreeMap<>();
        for (Map.Entry<IpPair, String> entry : originPair.entrySet()) {
            IpPair ipPair = entry.getKey();
            longIpMap.put(convertIpStr2Integer(ipPair.getBeginIpStr()), entry.getValue());
            longIpMap.put(convertIpStr2Integer(ipPair.getEndIpStr()), entry.getValue());
        }
        return longIpMap;
    }

    private static Integer convertIpStr2Integer(String ipStr) {
        int[] ips = new int[4];
        String[] parts = ipStr.split("\\.");
        for (int i = 0; i < parts.length; i++) {
            ips[i] = Integer.valueOf(parts[i]);
        }


        int ipNumber = 0;
        for (int i = 0; i < ips.length; i++) {
            ipNumber += (ips[i] << (24 - (8 * i)));
        }
        return ipNumber;
    }
}

class IpPair{
    private String beginIpStr;

    private String endIpStr;

    public IpPair(String beginIpStr, String endIpStr) {
        this.beginIpStr = beginIpStr;
        this.endIpStr = endIpStr;
    }

    public String getBeginIpStr() {
        return beginIpStr;
    }

    public String getEndIpStr() {
        return endIpStr;
    }

    @Override
    public boolean equals(Object obj) {
        IpPair ipPair = (IpPair) obj;
        return this.beginIpStr.equals(ipPair.getBeginIpStr()) && this.endIpStr.equals(ipPair.getEndIpStr());
    }

    @Override
    public int hashCode() {
        return Objects.hash(beginIpStr, endIpStr);
    }
}
